/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package index;

import java.io.File;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import stemmer.Stemmer;

/**
 *
 * @author Lu
 */
public class ElementHandler extends DefaultHandler {

    private ArrayList<Element> elementList;
    private ArrayList<String> typeList;
    private ArrayList<DepthAndCount> typeCounter;
    private ArrayList<Word> wordIndex;
    private ArrayList<StatsWordElement> currentElementStats;
    private ArrayList<ArrayList<StatsWordElement>> stats;
    private int depth;
    private String currentElement;
    private String currentElementType;
    private String documentName;
    private int currentPosition;
    private Stemmer stemmer;

    public ElementHandler() {
        super();
        elementList = new ArrayList<Element>();
        wordIndex = new ArrayList<Word>();
        stemmer = new Stemmer();
        stats = new ArrayList<ArrayList<StatsWordElement>>();
    }

    public void initNewFile(File file) {
        currentElement = null;
        documentName = file.getName();

        typeList = new ArrayList<String>();
        typeCounter = new ArrayList<DepthAndCount>();
        currentElement = "";
        depth = 0;
    }

    private int getTypeIndex(String type) {
        int i = Integer.MAX_VALUE;
        if (!typeCounter.isEmpty()) {
            i = typeCounter.size() - 1;
            while (i >= 0) {
                if ((typeCounter.get(i).getType().compareTo(type) == 0) && (typeCounter.get(i).getDepth() == depth)) {
                    break;
                } else {
                    i--;
                }
            }
        }

        return i;
    }

    private boolean typeIndexed(String type) {
        if (typeCounter.size() == 0) {
            return false;
        }
        for (int i = typeCounter.size() - 1; i > -1; i--) {
            if ((typeCounter.get(i).getType().compareToIgnoreCase(type) == 0) && (typeCounter.get(i).getDepth() == depth)) {
                return true;
            }
        }
        return false;
    }
    // balise detection
// WARNING this only works if a "balise" can only be on one depth

    @Override
    public void startElement(String uri, String localName,
            String qName, Attributes attributes) throws SAXException {

        currentPosition = 1;

        currentElementStats = new ArrayList<StatsWordElement>();

        /*-----------------------------------------------*/
        depth++;
        int newCount;

        // if the type is already indexed
        if (typeIndexed(qName)) {
            // we get its index
            int index = getTypeIndex(qName);
            // if it was on lower depth, we restart the counter to 1
            typeCounter.get(index).addOne();
            newCount = typeCounter.get(index).getCount();
        } else {
            typeList.add(qName);
            newCount = 1;
            typeCounter.add(new DepthAndCount(qName, depth, 1));
        }
        currentElementType = qName;
        currentElement = currentElement.concat("/" + qName + "[" + newCount + "]");
        elementList.add(new Element(currentElement, qName, documentName));
    }

    // end balise detection
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {

        resetDeepElements();
        substractQName(qName);
        currentElement.lastIndexOf(qName);

        for (StatsWordElement s : currentElementStats) {
            s.computeTfIdf(currentPosition);
        }
        stats.add(currentElementStats);

        currentElementStats = new ArrayList<StatsWordElement>();

        depth--;
    }

    public void substractQName(String qName) {
        int index = currentElement.lastIndexOf("/" + qName);
        currentElement = currentElement.substring(0, index);
    }

    public void resetDeepElements() {
        for (int i = 0; i < typeCounter.size(); i++) {
            if (typeCounter.get(i).getDepth() > depth) {
                typeCounter.get(i).reset();

            }
        }
    }

    private void updateStats(String stemmeredWord) {
        boolean newOne = true;
        for (StatsWordElement s : currentElementStats) {
            if (s.getWord().compareToIgnoreCase(stemmeredWord) == 0) {
                newOne = false;
                s.addOne();
                break;
            }
        }
        if (newOne) {
            currentElementStats.add(new StatsWordElement(currentElement, documentName, stemmeredWord));
        }
    }

    //détection de caractères
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        String read = new String(ch, start, length);
        String words[] = read.split("[';, .\"()\\?\\/:{}\\[\\]\"»«!%\\-*²^€$=+_\\\n<>’…– \\\\½¼…–]");
        boolean wordIndexed = false;
        Word wordFound = null;
        String stemmeredWord;
        StopList sl = new StopList("..\\stopliste.txt");
        // going through all words read in the current "balise"
        for (String currentWord : words) {
            // in case we get empty word
            currentWord = currentWord.trim();
            if ((currentWord.compareTo("") == 0)
                    || (currentWord.compareTo(" ") == 0)) {
                continue;
            }

            // Remove word if it is in the stoplist
            String stopWord;
            boolean toKeep = true;
            Iterator<String> it = sl.getStopListArray().iterator();
            while (it.hasNext()) {
                stopWord = it.next();
                if (currentWord.equalsIgnoreCase(stopWord)) {
                    toKeep = false;
                }
            }
            if (!toKeep) {
                continue;
            }

            // we stemmer the word !
            currentWord = currentWord.toLowerCase();
            stemmeredWord = stemmer.stemWord(currentWord);

            // remove accents
            stemmeredWord = Normalizer.normalize(stemmeredWord, Normalizer.Form.NFD).replaceAll(
                    "\\p{InCombiningDiacriticalMarks}+", "");
            currentWord = Normalizer.normalize(currentWord, Normalizer.Form.NFD).replaceAll(
                    "\\p{InCombiningDiacriticalMarks}+", "");

           currentElement = currentElement.replaceAll("œ", "oe");
           stemmeredWord = stemmeredWord.replaceAll("œ", "oe");
            if(stemmeredWord.compareToIgnoreCase("cœur")==0){
                System.out.println("WHAAAAAAAAAAAAAAAAAAAAAAAT");
            }
            // we update stats in this element for this word
            updateStats(stemmeredWord);

            wordIndexed = false;
            // searching if the word already exist
            for (Word indexedWord : wordIndex) {
                // if we find it, we stop our search
                if (indexedWord.getName().compareToIgnoreCase(stemmeredWord) == 0) {
                    wordIndexed = true;
                    wordFound = indexedWord;
                    break;
                }
            }
            // if it does, update its statistics
            if (wordIndexed) {
                updateWord(wordFound, currentWord);
            } // else, add it the the indexed list
            else {
                addWord(stemmeredWord, currentWord.toLowerCase());
            }
            // incrementing the new position
            currentPosition++;
        }
    }

    // Method to update a word from the index
    private void updateWord(Word word, String fullWord) {
        word.addOne(fullWord, currentElement, currentElementType, documentName, currentPosition);
    }

    // Method to add a word to the index
    private void addWord(String stemmeredWord, String fullWord) {
        Word word = new Word(stemmeredWord, fullWord, currentElement, currentElementType, documentName, currentPosition);
        wordIndex.add(word);
//        System.out.println(stemmeredWord);
    }

    //début du parsing
    @Override
    public void startDocument() throws SAXException {
//        System.out.println("Début du parsing");
    }
    //fin du parsing

    @Override
    public void endDocument() throws SAXException {
//        System.out.println("Fin du parsing");
//        System.out.println("Resultats du parsing");
//        for (Element p : elementList) {
//            System.out.println(p);
//        }
    }

    public ArrayList<Word> getWordIndex() {
        return wordIndex;
    }

    public String getDocumentName() {
        return documentName;
    }

    public ArrayList<Element> getElementList() {
        return elementList;
    }

    public ArrayList<String> getTypeList() {
        return typeList;
    }

    public ArrayList<ArrayList<StatsWordElement>> getStats() {
        return stats;
    }
}
